package com.rub.prajna.core.util;

import com.github.junrar.Archive;
import com.github.junrar.rarfile.FileHeader;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.tools.zip.ZipEntry;
import org.apache.tools.zip.ZipFile;
import org.apache.tools.zip.ZipOutputStream;

import java.io.*;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;
import java.nio.file.Files;
import java.text.DecimalFormat;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.List;

import static java.lang.System.out;

public class FileUtil {
    public static final int BUFSIZE = 1024 * 8;

    /**
     * 读取文件内容并返回为字符串
     *
     * @deprecated 使用 {@link FileUtils#readFileToString(File, Charset)}
     */
    public static String readText(File file, Charset charset) {
        try {
            return new String(Files.readAllBytes(file.toPath()), charset);
        } catch (IOException e) {
            e.printStackTrace();
            return "";
        }
    }

    /**
     * 读取文件内容，按默认编码解析，并返回为字符串
     *
     * @deprecated 使用 {@link FileUtils#readFileToString(File, Charset)}
     */
    public static String readText(File file) {
        return readText(file, Charset.defaultCharset());
    }

    /**
     * 将文件名拆分成名字部分和扩展名部分
     *
     * @deprecated 使用 {@link FilenameUtils#getExtension(java.lang.String)}
     */
    public static String[] getFileNames(File file) {
        String fileName = file.getName();
        return new String[]{
            StringUtils.substringBeforeLast(fileName, "."),
            StringUtils.substringAfterLast(fileName, ".")
        };
    }

    /**
     * @deprecated 使用 {@link FilenameUtils#getBaseName(java.lang.String)}
     */
    public static String getFileName(File file) {
        return getFileNames(file)[0];
    }

    /**
     * @deprecated 使用 {@link FilenameUtils#getExtension(java.lang.String)}
     */
    public static String getFileSuffixName(File file) {
        return getFileNames(file)[1];
    }

    /**
     * @deprecated 使用 {@link org.apache.commons.io.FilenameUtils}
     */
    public static String getFileSuffixNameAndDot(File file) {
        String suffixName = getFileNames(file)[1];
        if (!"".equals(suffixName)) {
            suffixName = "." + suffixName;
        }
        return suffixName;
    }

    public static String getRandomFileName(File file) {
        String[] fileNames = getFileNames(file);
        String fileName = fileNames[0] + ("" + System.currentTimeMillis()).substring(9);
        if (!"".equals(fileNames[1])) {
            fileName += ("." + fileNames[1]);
        }
        return fileName;
    }

    /**
     * 转换文件的大小以B,KB,M,G等计算
     *
     * @deprecated 使用 {@link FileUtils#byteCountToDisplaySize(java.math.BigInteger)}
     */
    public static String formatFileSize(long fileS) {// 转换文件大小
        DecimalFormat df = new DecimalFormat("#.000");
        String fileSizeString = "";
        if (fileS < 1024) {
            fileSizeString = df.format((double) fileS) + "B";
        } else if (fileS < 1048576) {
            fileSizeString = df.format((double) fileS / 1024) + "K";
        } else if (fileS < 1073741824) {
            fileSizeString = df.format((double) fileS / 1048576) + "M";
        } else {
            fileSizeString = df.format((double) fileS / 1073741824) + "G";
        }
        return fileSizeString;
    }


    /**
     * 将内容写入到一个文件
     *
     * @param filePath 文件的全路径
     * @param content  文件内容
     * @param chartset 字符集
     * @throws Exception
     */
    public static void writeToFile(String filePath, String content, String chartset) throws Exception {
        if (chartset == null || "".equals(chartset.trim())) {
            chartset = "UTF-8";
        }
        File file = new File(filePath);
        Writer writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), chartset));
        writer.write(content);
        writer.flush();
        writer.close();
    }

    /**
     * 读取文件内容
     *
     * @param filePath
     * @param chartset
     * @return
     * @throws Exception
     */
    public static String readFromFile(String filePath, String chartset) throws Exception {
        if (chartset == null || "".equals(chartset.trim())) {
            chartset = "UTF-8";
        }
        File file = new File(filePath);
        BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), chartset));
        StringBuilder contentBuilder = new StringBuilder();
        String line = null;
        while ((line = reader.readLine()) != null) {
            contentBuilder.append(line);
            contentBuilder.append("\n");
        }
        reader.close();
        return contentBuilder.toString();
    }

    /**
     * 列出文件清单,以一个数组形式返回，
     *
     * @param filePath 磁盘文件路径
     * @param fileArr  此参数需要传一个new ArrayList<>()进入方法体,在方法体创建一个对象数组，子目录的文件存放不了进数组进行返回
     * @return List<String>
     */
    public static List<String> listFiles(String filePath, List<String> fileArr) {
        File[] files = new File(filePath).listFiles();
        for (int k = 0; k < files.length; k++) {
            if (files[k].isDirectory()) {
                listFiles(files[k].getPath(), fileArr);
            } else if (!files[k].isDirectory()) {
                fileArr.add(files[k].getAbsolutePath());
            }
        }
        return fileArr;
    }

    /**
     * 多个文件进行合并
     *
     * @param outFile
     * @param files
     */
    public static void mergeFiles(String outFile, String[] files) {
        FileChannel outChannel = null;
        out.println("Merge " + Arrays.toString(files) + " into " + outFile);
        try {
            outChannel = new FileOutputStream(outFile).getChannel();
            for (String f : files) {
                Charset charset = Charset.forName("utf-8");
                CharsetDecoder chdecoder = charset.newDecoder();
                CharsetEncoder chencoder = charset.newEncoder();
                FileChannel fc = new FileInputStream(f).getChannel();
                ByteBuffer bb = ByteBuffer.allocate(BUFSIZE);
                CharBuffer charBuffer = chdecoder.decode(bb);
                ByteBuffer nbuBuffer = chencoder.encode(charBuffer);
                while (fc.read(nbuBuffer) != -1) {
                    bb.flip();
                    nbuBuffer.flip();
                    outChannel.write(nbuBuffer);
                    bb.clear();
                    nbuBuffer.clear();
                }
                fc.close();
            }
            out.println("Merged!! ");
        } catch (IOException ioe) {
            ioe.printStackTrace();
        } finally {
            try {
                if (outChannel != null) {
                    outChannel.close();
                }
            } catch (IOException ignore) {
            }
        }
    }


    /**
     * 不解压
     */
    public static void unRarFile(String srcRarPath, String dstDirPath) {
        if (!srcRarPath.toLowerCase().endsWith(".rar")) {
            out.println("非rar文件！");
            return;
        }
        File dstDiretory = new File(dstDirPath);
        // 目标目录不存在时，创建该文件夹
        if (!dstDiretory.exists()) {
            dstDiretory.mkdirs();
        }
        Archive archive = null;
        try {
            if (archive == null) {
                out.println("archive null！");
                return;
            }
            archive.getMainHeader().print(); // 打印文件信息.
            FileHeader fileHeader = archive.nextFileHeader();

            while (fileHeader != null) {
                if (fileHeader.isDirectory()) { // 文件夹
                    File fol = new File(dstDirPath + File.separator + fileHeader.getFileName());
                    fol.mkdirs();
                } else {
                    File out = new File(dstDirPath + File.separator + fileHeader.getFileName().trim());

                    // 之所以这么写try，是因为万一这里面有了异常，不影响继续解压.
                    if (!out.exists()) {
                        if (!out.getParentFile().exists()) {// 相对路径可能多级，可能需要创建父目录.
                            out.getParentFile().mkdirs();
                        }
                        out.createNewFile();
                    }
                    FileOutputStream os = new FileOutputStream(out);
                    archive.extractFile(fileHeader, os);
                    os.close();

                }
                fileHeader = archive.nextFileHeader();
            }
            archive.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 压缩文件
     *
     * @param srcfile File[] 需要压缩的文件列表
     * @param zipfile File 压缩后的文件
     */
    public static void ZipFiles(java.io.File[] srcfile, java.io.File zipfile) {
        byte[] buf = new byte[1024];

        try {
            ZipOutputStream out = new ZipOutputStream(new FileOutputStream(zipfile));

            for (int i = 0; i < srcfile.length; i++) {
                FileInputStream in = new FileInputStream(srcfile[i]);
                out.putNextEntry(new ZipEntry(srcfile[i].getName()));
                String str = srcfile[i].getName();
                int len;
                while ((len = in.read(buf)) > 0) {
                    out.write(buf, 0, len);
                }
                out.closeEntry();
                in.close();
            }
            out.close();
            System.out.println("压缩完成.");
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    /**
     * zip解压缩
     *
     * @param zipfile File 需要解压缩的文件
     * @param descDir String 解压后的目标目录
     */
    public static void unZipFiles(java.io.File zipfile, String descDir) {
        try {
            ZipFile zf = new ZipFile(zipfile);
            for (Enumeration entries = zf.getEntries(); entries.hasMoreElements(); ) {
                ZipEntry entry = ((ZipEntry) entries.nextElement());
                String zipEntryName = entry.getName();
                InputStream in = zf.getInputStream(entry);
                OutputStream out = new FileOutputStream(descDir + zipEntryName);
                byte[] buf1 = new byte[1024];

                int len;
                while ((len = in.read(buf1)) > 0) {
                    out.write(buf1, 0, len);
                }
                in.close();
                out.close();
                System.out.println("解压缩完成.");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 通过文件路径，获取文件名
     *
     * @param inputFilePath
     * @return
     */
    @Deprecated
    public static String getFileName(String inputFilePath) {
        boolean slashLeft = inputFilePath.contains("/");
        //切割路径
        String[] slashArr = null;
        if (slashLeft) {
            slashArr = inputFilePath.split("/");
        } else {
            slashArr = inputFilePath.split("\\\\");
        }
        return slashArr[slashArr.length - 1];
    }

    /**
     * @param path
     * @return
     */
    public static File[] getFiles(String path) {
        File file = new File(path);
        File[] files = file.listFiles();
        return files;
    }

    public static void mkDirs(String cutDirs) {
        File srcFile = new File(cutDirs);
        boolean flag = srcFile.exists();
        /**
         * @flag判断文件是否存在
         * @isDirectory测试此抽象路径名表示的文件是否是一个目录
         * @canWrite测试应用程序是否可以读取此抽象路径名表示的文件
         */
        if (!flag || !srcFile.isDirectory() || !srcFile.canRead()) {
            try {
                srcFile.mkdirs();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * Convert from a filename to a file URL.
     */
    public static String convertToFileURL(String filename) {
        // On JDK 1.2 and later, simplify this to:
        // "path = file.toURL().toString()".
        String path = new File(filename).getAbsolutePath();
        if (File.separatorChar != '/') {
            path = path.replace(File.separatorChar, '/');
        }
        if (!path.startsWith("/")) {
            path = "/" + path;
        }
        String retVal = "file:" + path;
        return retVal;
    }

    
}
